Note 6 Functional Dependency Theory

Author: Zhen Tong 120090694@link.cuhk.edu.cn
Lecturer: Jan YOU

To better understand this chapter, you are encourage to play the functional dependency calculator with lab2 on my githubヾ(≧▽≦*)o

Closure of a FDs set

In the last note we learned the concept of closure of a set of functional dependencies. Now let’s see how to derive a F+F^+

We can compute F+F^+ by repeatedly applying Armstrong’s Axioms.

According to the Armstrong’s Axioms there are 3 additional rules inferred.

The following computes the closure of a set of functional dependencies F

Closure of Attribute Sets

Given a set of attributes α\alpha, define the closure of α\alpha under F (denoted byα+\alpha+) as the set of attributes that are functionally determined by α\alpha under F

The pseudo-code is like:

def sub_closure(self, sub_attrs:set):
    '''
    Given a set of attributes alpha, define the closure of alpha+ under F 
    '''
    result = set()
    result_prime = set(a for a in sub_attrs)
    while len(result) != len(result_prime):
        # copy the prime to origin
        result = set(a for a in result_prime)
        # print("result = ", result)
        for fd in self.FDs:
            if fd.alpha.issubset( result) :
                result_prime = result_prime.union(fd.beta)
                # print("Unioned:", result_prime)
        print("result", result)
    return result

Example of Attribute Set Closure

R=(A,B,C,G,H,I)R = (A, B, C, G, H, I)

F={AB,AC,CGH,CGI,BH}F = \{A \rightarrow B, A \rightarrow C , CG \rightarrow H, CG \rightarrow I, B \rightarrow H\}

We can find the Closure of Attribute Sets with the function:

There are several uses of the attribute closure algorithm:

Canonical Cover

A canonical cover is a minimal and simplified set of functional dependencies that has the same closure as the original set of functional dependencies on a relation schema. It is used to make it more efficient to ensure that functional dependencies are not violated when updates are performed on the database.

In one word, canonical cover is summary the essence of a set of FD

  1. Ensuring FD Satisfaction: When updates (inserts, updates, deletes) are performed on the database, the database system needs to ensure that these updates do not violate any of the functional dependencies in the set F. If an update would cause a violation, it must be rolled back to maintain data consistency.
  1. Canonical Cover for Efficiency: To make the process of checking for violations more efficient, you can create a simplified set of functional dependencies known as the "canonical cover." The canonical cover contains only the essential functional dependencies required to represent the same closure (the set of all FDs derivable from F).

Extraneous Attributes: To construct the canonical cover, you must identify and eliminate extraneous attributes. An attribute in a functional dependency in F is extraneous if you can remove it without changing the closure of F. In other words, it doesn't contribute to the uniqueness of the attribute values.

Test if an Attribute is Extraneous

Let R be a relation schema and let F be a set of functional dependencies that hold on R . Consider an attribute in the functional dependency αβ\alpha\rightarrow\beta

To test if attribute AβA\in\beta is extraneous in β\beta

To test if attribute AαA\in\alpha is extraneous in α\alpha

In python the code is:

def is_extranious(self, fd:FunctionalDependency, A:set, determinant:bool):
        alpha = copy.deepcopy(fd.alpha)
        beta = copy.deepcopy(fd.beta)
        if determinant:
            gamma = alpha.difference(A)
            gamma_plus = self.sub_closure(gamma)
            if beta.issubset(gamma_plus):
                return True
            else:
                return False
        else:   
            F= set(i for i in self.FDs)
            F_prime = (F.difference({fd})).union({FunctionalDependency(alpha, beta.difference(A))})
            alpha_plus = self.sub_closure(alpha, F_prime)
            if A.issubset(alpha_plus):
                return True
            else:
                return False

Now we can compute the Canonical Cover

A canonical cover for F is a set of dependencies Fc such that:

To compute a canonical cover for F

The first thing during the loop is satisfying the fourth rule in Canonical Cover. And whenever there is a new functional dependency established based on that, the old two functional dependencies are useless.

The second thing during the loop is satisfying the third rule in Canonical Cover.

Dependency Preservation

If we decompose the relation schema RR into [R1,...,Rn][R_1, ..., R_n], the restriction of the functional dependency set FF to RiR_i is the set FiF_i of all functional dependencies in F+that include only attributes of R

A decomposition is dependency-preserving, if(F1F2...Fn)+=F+(F_1\cup F_2\cup ...\cup F_n)^+ = F^+

BCNF Decomposition Algorithm

In the algorithm above, we need to first check whether the decomposed relational schema RiR_i in the results is BCNF. We can do any one of the two things:

Then we come back to the BCNF Decomposition Algorithm, after we detect one functional dependency αβ\alpha\rightarrow\beta is violating the BCNF in the RiR_i, we do the decomposition of RiR_i into RiβR_i-\beta and {α,β}\{\alpha, \beta\}

Did you notice that the algorithm doesn’t check the Dependency Preservation, it doesn’t merge all the restriction FiF_i of the RiR_i to see if the (F1F2...Fn)+=F+(F_1\cup F_2\cup ...\cup F_n)^+ = F^+ holds.

BCNF or 3NF

There are some situations where

We can use the Third Normal Form (3NF)

3NF Decomposition Algorithm

Before we introduce the 3NF Decomposition Algorithm, let’s first recap the 3NF definition:

We know BCNF is a sufficient set of 3NF, i.e. if a relational schema is a BCNF, it is a 3NF. Now let’s have a look at the 3NF decomposition.